-- SPDX-License-Identifier: GPL-3.0-or-later

--------------------------------------------------
--换牌期间无效化所有技能（白银狮子那个算不算技能啊kusa）
--------------------------------------------------

local Swap_Invalidity = fk.CreateInvaliditySkill {
  name = "Swap_Invalidity",
  global = true,
  invalidity_func = function(self, from, skill)
    return
      from:getMark("swap_invalid") > 0
  end
}

--------------------------------------------------
--本回合造成多少伤害
--------------------------------------------------

local damage_checker_turn = fk.CreateTriggerSkill{
  name = "#damage_checker_turn",
  global = true,
  refresh_events = {fk.Damage},
  can_refresh = function(self, event, target, player, data)
    return target == player
  end,
  on_refresh = function(self, event, target, player, data)
    local room = player.room
    local damage = data
    -- print(damage.damage)
    room:addPlayerMark(player, "#turn_damage-turn", damage.damage)
  end,
  }

-- Fk:addSkill(damage_checker_turn)

--------------------------------------------------
--本回合（被）某个角色指定为目标
--注释:
-- 在三国杀中，一名角色使用牌指定N个目标，将会产生N个“指定目标时”"指定目标后”时机。
-- 在Vup杀中，一名角色使用牌指定N个目标，只会产生1个“指定目标时”“指定目标后”时机。
-- 在三国杀中的“你使用牌指定一名角色为目标后”将会依次询问对每名目标是否发动技能。
-- 在Vup杀中，类似技能通常会对所有目标同时生效，或询问玩家要对哪名目标发动技能。
-- 因此targetspecified是多次分别指定所有目标，其他Vup杀技能在处理这个问题时需要携带data.firstTarget.
--------------------------------------------------

local target_specified_check = fk.CreateTriggerSkill{
  name = "#target_specified_check",
  global = true,
  --时机：目标确定后
  refresh_events = {fk.TargetSpecified},
  --触发条件：触发时机的角色为遍历到的角色
  can_refresh = function(self, event, target, player, data)
    return target == player and data.firstTarget
  end,
  on_refresh = function(self, event, target, player, data)
    local room = player.room
    local tars = AimGroup:getAllTargets(data.tos)
    local tar
    -- local pp
    local targets = {}
    local players = {}
    if player:getMark("#specified_target-turn") ~= 0 then
      targets = player:getMark("#specified_target-turn")
    end
    for _,p in ipairs(tars) do
      tar = room:getPlayerById(p)
      if tar:getMark("#target_specified-turn") ~= 0 then
        players = tar:getMark("#target_specified-turn")
      end
      table.insertIfNeed(players, player.id)
      -- pp = table.concat(players, "+")
      table.insertIfNeed(targets, tar.id)
      -- local tt = table.concat(targets, "+")
      --为目标的记录中增加本回合指定过自己的角色
      room:setPlayerMark(tar, "#target_specified-turn", players)
      --为遍历到的角色的记录中增加本回合已指定的目标
      room:setPlayerMark(player, "#specified_target-turn", targets)
      --（测试用）
      -- room:setPlayerMark(tar, "@target_specified-turn", pp)
      -- room:setPlayerMark(player, "@specified_target-turn", tt)
    end
    --测试用
    -- if player:getMark("@specified_target-turn") ~= {} then
    --   targets = player:getMark("@specified_target-turn")
    -- end
    -- if target:getMark("@target_specified-turn") ~= {} then
    --   players = target:getMark("@target_specified-turn")
    -- end
  end,
}

-- Fk:addSkill(target_specified_check)

--------------------------------------------------
--本局游戏中使用的总牌数。
--适用范围：三叹等。
--注释：根据三叹可以确认，Fk类的技能同时机优先级低于当前回合逆时针角色，其余不确定。
--------------------------------------------------

local card_use_checker = fk.CreateTriggerSkill{
  name = "#card_use_checker",
  global = true,
  --时机：卡牌使用宣告后
  -- refresh_events = {fk.CardUseFinished},
  refresh_events = {fk.AfterCardUseDeclared},
  can_refresh = function(self, event, target, player, data)
    return target == player
  end,
  on_refresh = function(self, event, target, player, data)
    local room = player.room
    room:addPlayerMark(player, "card_used", 1)
  end,
}

-- Fk:addSkill(card_use_checker)

--------------------------------------------------
--标记清理者。
--涉及：获得/失去技能时的标记清理（待定，会涉及无忌和袭穴），
--      离开手牌/进入弃牌堆/拥有者变化清理cardmark【在mark末尾前加上-cardmark!ldc*，ldc根据代码需要填写】。
--如果后续不能在mark名字上加特殊符号的处理方案：此类技能在游戏开始/获得技能的时候用insertifneed将这种标记增加在指定的roomtag里，后续每一次遍历牌上的mark是否在roomtag里，在则触发。
--------------------------------------------------

local mark_cleaner = fk.CreateTriggerSkill{
  name = "#mark_cleaner",
  global = true,
  --时机：
  -- refresh_events = {fk.EventAcquireSkill, fk.EventLoseSkill, fk.AfterCardsMove},
  refresh_events = {fk.AfterCardsMove},
  --刷新时机：
  --卡牌移动后：
  --①离手
  --②进入弃牌堆
  --③持有者变化
  can_refresh = function(self, event, target, player, data)
    if event == fk.AfterCardsMove then
      for _, move in ipairs(data) do
        if move.toArea == Card.DiscardPile 
          or (move.from and move.fromArea == Card.PlayerHand and move.toArea ~= Card.PlayerHand)
          or (move.from and move.to and move.from ~= move.to)
        then
          return true
        end
      end
    end
    -- return target == player
  end,
  on_refresh = function(self, event, target, player, data)
    local room = player.room
    if event == fk.AfterCardsMove then
      for _, p in ipairs(room:getAllPlayers()) do
				if p:getMark("v_Not_clear_card_flag") > 0 then return false end	--有Not_clear_card_flag这个flag存在时，不会清除cardflag
			end
      for _, move in ipairs(data) do
        --离手触发。
        if move.from and move.fromArea == Card.PlayerHand and move.toArea ~= Card.PlayerHand then
          for _, info in ipairs(move.moveInfo) do
            for name, _ in pairs(Fk:getCardById(info.cardId).mark) do
              local _,cms = name:find("-cm!")
              local cme,_ = name:find("*")
              if cms and cme and cms < cme then
                local cm = name:sub(cms, cme)
                if cm:find("l") then
                  room:setCardMark(Fk:getCardById(info.cardId), name, 0)
                end
              end
            end
          end
        end
        --进入弃牌堆触发。
        if move.toArea == Card.DiscardPile then
          for _, info in ipairs(move.moveInfo) do
            for name, _ in pairs(Fk:getCardById(info.cardId).mark) do
              local _,cms = name:find("-cm!")
              local cme,_ = name:find("*")
              if cms and cme and cms < cme then
                local cm = name:sub(cms, cme)
                if cm:find("d") then
                  room:setCardMark(Fk:getCardById(info.cardId), name, 0)
                end
              end
            end
          end
        end
        --持有者变化触发。
        if move.from and move.to and move.from ~= move.to then
          for _, info in ipairs(move.moveInfo) do
            for name, _ in pairs(Fk:getCardById(info.cardId).mark) do
              local _,cms = name:find("-cm!")
              local cme,_ = name:find("*")
              if cms and cme and cms < cme then
                local cm = name:sub(cms, cme)
                if cm:find("c") then
                  room:setCardMark(Fk:getCardById(info.cardId), name, 0)
                end
              end
            end
          end
        end
      end
    end
  end,
}

--------------------------------------------------
--私家牌堆清理者。
--涉及：临时除外的牌返回玩家牌区；如果不符合要求的将进入弃牌堆。【在mark末尾前加上-pile!tr*，tr根据代码需要填写】。
--如果后续不能在mark名字上加特殊符号的处理方案：此类技能在游戏开始/获得技能的时候用insertifneed将这种标记增加在指定的roomtag里，后续每一次遍历私家牌堆上的名字是否在roomtag里，在则触发。
--后续看看死人了之后这种牌会不会自己被清理掉，应该会？
--------------------------------------------------

local pile_cleaner = fk.CreateTriggerSkill{
  name = "#pile_cleaner",
  global = true,
  --时机：
  -- refresh_events = {fk.EventAcquireSkill, fk.EventLoseSkill, fk.AfterCardsMove},
  refresh_events = {
    fk.EventPhaseChanging
  },
  --刷新时机：
  --阶段变化时：
  -- ···
  can_refresh = function(self, event, target, player, data)
    if event == fk.EventPhaseChanging then
      return data.from ~= Player.NotActive and data.to == Player.NotActive
    end
    -- return target == player
  end,
  on_refresh = function(self, event, target, player, data)
    local room = player.room
    if event == fk.EventPhaseChanging then
      for _,p in ipairs(room:getAllPlayers()) do
        for pile_name,pile_cards in pairs(p.special_cards) do
          local _,pis = pile_name:find("-pile!")
          local pie,_ = pile_name:find("*")
          if (pis and pie and pis < pie) and #pile_cards > 0 then
            local pi = pile_name:sub(pis, pie)
            if pi:find("t") then
              local ids = {}
              local places = {}
              if p:getMark(pile_name.."_ids") ~= 0 then
                ids = p:getMark(pile_name.."_ids"):split("+")
                room:sendLog{
                  type = "#v_banish_log",
                  from = p.id,
                  arg = pile_name,
                  arg2 = #ids,
                }
              end
              if p:getMark(pile_name.."_places") ~= 0 then
                places = p:getMark(pile_name.."_places"):split("+")
              end
              local hands, equips, delaytricks, removecards =
                Fk:cloneCard("dilu"), Fk:cloneCard("dilu"), Fk:cloneCard("dilu"), Fk:cloneCard("dilu")
              for i = 1, #ids, 1 do
                --Card.PlayerHand = 1
                if places[i] == tostring(1) then
                  hands:addSubcard(tonumber(ids[i]))
                --Card.PlayerEquip:2
                elseif places[i] == tostring(2) then
                  local card = Fk:getCardById(ids[i])
                  local location = card.sub_type
                  if location and p:getEquipment(location) and #p:getAvailableEquipSlots(location) > 0 then
                    equips:addSubcard(tonumber(ids[i]))
                  else
                    removecards:addSubcard(tonumber(ids[i]))
                  end
                --Card.PlayerJudge:3
                elseif places[i] == tostring(3) then
                  local card = Fk:getCardById(tonumber(ids[i]))
                  if 
                    not (
                      table.find(p:getCardIds(Player.Judge), function(cardId)
                        return Fk:getCardById(cardId).name == card.name
                      end) or
                      table.contains(p.sealedSlots, Player.JudgeSlot)
                    )
                  then
                    equips:addSubcard(tonumber(ids[i]))
                  else
                    removecards:addSubcard(tonumber(ids[i]))
                  end
                --这里后续增加其他类型牌的判定方式
                end
              end
              if #hands.subcards > 0 then
                room:moveCardTo(hands, Card.PlayerHand, p)
                -- room:moveCardTo(hands, Player.Hand, p)
              end
              if #equips.subcards > 0 then
                room:moveCardTo(equips, Card.PlayerEquip, p)
              end
              if #delaytricks.subcards > 0 then
                room:moveCardTo(delaytricks, Card.PlayerJudge, p)
              end
              if #removecards.subcards > 0 then
                room:throwCard(removecards, nil, p, p)
              end
              room:setPlayerMark(p, pile_name.."_ids", 0)
              room:setPlayerMark(p, pile_name.."_places", 0)
            end
          end
        end
      end
    end
  end,
}

--------------------------------------------------
--特殊机制：真实轮次
--------------------------------------------------

local v_trueround = fk.CreateTriggerSkill{
  name = "v_trueround",
  priority = 11,
  global = true,
  refresh_events = {fk.GamePrepared, fk.RoundStart, fk.RoundEnd},
  --触发条件：
  -- ...
  can_refresh = function(self, event, target, player, data)
    local room = player.room
    if not room:getTag("FirstRound") then
      if event == fk.GamePrepared then
        return true
      elseif event == fk.RoundStart then
        return not room:getTag("trueround_used")
      elseif event == fk.RoundEnd then
        return true
      end
    end
  end,
  on_refresh = function(self, event, target, player, data)
    local room = player.room
    local X = room:getTag("v_trueround")
    if event == fk.GamePrepared then
      room:setTag("v_trueround", 0)
      room:setTag("trueround_used", false)
    elseif event == fk.RoundStart then
      room:setTag("v_trueround", X + 1)
      for _, p in ipairs(room:getAllPlayers()) do
        room:setPlayerMark(p, "@v_trueround", room:getTag("v_trueround"))
      end
      room:setTag("trueround_used", true)
    elseif event == fk.RoundEnd then
      room:setTag("trueround_used", false)
    end
  end,
}

--------------------------------------------------
--特殊机制：过劳机制
--本写法下，可能在多并发的前提下降低游戏的运行效率，如非所有模式都可能用到，建议避免使用本函数。
--------------------------------------------------

local v_noexhaustion = function(player)
  if player:hasSkill("#v_characteristic_aihaoshishuijiao", true) then
    return true
  end
  return false
end

local v_exhaustion = fk.CreateTriggerSkill{
  name = "v_exhaustion",
  -- priority = 11,
  global = true,
  -- mute = true,
  -- frequency = Skill.Compulsory,
  -- anim_type = "special",
  refresh_events = {fk.GameStart, fk.RoundStart, fk.RoundEnd, fk.EventPhaseEnd},
  --触发条件：
  -- ...
  can_refresh = function(self, event, target, player, data)
    local room = player.room
    if room.settings.gameMode == "v_m_1v2_mode" then
      if event == fk.GameStart then
        return true
      elseif event == fk.RoundStart then
        return room:getTag("v_trueround") > 18 and not room:getTag("trueround_rule_used")
      elseif event == fk.RoundEnd then
        return true
      elseif event == fk.EventPhaseEnd then
        return target == player and player.phase == Player.Finish
      end
    elseif room.settings.gameMode == "v_m_2v2_mode" then
      if event == fk.GameStart then
        return true
      elseif event == fk.RoundStart then
        return room:getTag("v_trueround") > 16 and not room:getTag("trueround_rule_used")
      elseif event == fk.RoundEnd then
        return true
      elseif event == fk.EventPhaseEnd then
        return target == player and player.phase == Player.Finish
      end
    end
    --  and target == nil
  end,
  on_refresh = function(self, event, target, player, data)
    local room = player.room
    local X = room:getTag("v_trueround")
    if event == fk.GameStart then
      room:setTag("trueround_rule_used", false)
    elseif event == fk.RoundStart then
      room:setTag("trueround_rule_used", true)
      for _, p in ipairs(room:getAllPlayers()) do
        --这里后续可以加入特殊疲劳机制判定（例如秋凛子）
        -- if p:getMark("@@v_exhaustion") == 0 and p:getMark("v_noexhaustion") == 0 then
        if p:getMark("@@v_exhaustion") == 0 and not v_noexhaustion(p) then
          room:setPlayerMark(p, "@@v_exhaustion", 1)
        -- elseif p:getMark("@@v_noexhaustion") == 0 and p:getMark("v_noexhaustion") > 0 then
        elseif p:getMark("@@v_noexhaustion") == 0 and v_noexhaustion(p) then
          room:setPlayerMark(p, "@@v_noexhaustion", 1)
        end
      end
    elseif event == fk.RoundEnd then
      room:setTag("trueround_rule_used", false)
    elseif event == fk.EventPhaseEnd then
      local v_phoenix = false
      if player:getMark("@@v_exhaustion") > 0 and player:isAlive() then
        --这里后续可以加入特殊疲劳机制判定（例如秋凛子）
        --这里后续可以加入每回合增加的弹幕/战报文案
        -- if player:getMark("v_phoenix") > 0 then
        for _, p in ipairs(room:getAllPlayers()) do
          if player:hasSkill("#v_characteristic_niepan", true) then
            v_phoenix = true
          end
        end
        if v_phoenix then
          room:drawCards(player, 2, self.name)
          room:damage{
            to = player,
            damage = 1,
            damageType = fk.FireDamage,
            skillName = self.name,
          }
        else
          room:loseHp(player, 1)
        end
      end
    end
  end,
}

--------------------------------------------------
--特殊机制：冰霜伤害
--------------------------------------------------

local v_ice_type_damage = fk.CreateTriggerSkill{
  --（刚需）技能认证名
  name = "v_ice_type_damage",
  global = true,
  -- mute = true
  --技能为锁定技，满足条件后强制发动
  frequency = Skill.Compulsory,
  --时机：造成伤害时
  events = {fk.DamageCaused},
  --触发条件：
  --（造成伤害时）触发时机的角色为遍历到的角色，
  --             造成的伤害大于0, 伤害种类为冰属性，
  --             伤害来源存在且在场。
  --             伤害目标存在且在场。
  --             来源可以弃置目标牌（看情况补，先补有牌）。
  can_trigger = function(self, event, target, player, data)
    --local room = player.room
    return 
      (data.damage > 0 and data.damageType == fk.IceDamage) 
      and target == player and player and player == data.from and player:isAlive()
      -- and data.from and data.from:isAlive()
      and data.to and data.to:isAlive()
      and not data.to:isNude()
  end,
  on_use = function(self, event, target, player, data)
    local room = player.room
    local prompt = "#v_ice_type_damage_choice:"..data.to.id
    -- if room:askForSkillInvoke(data.from, self.name, data, prompt) then
    if room:askForSkillInvoke(player, self.name, data, prompt) then
      local room = player.room
      room:sendLog{
        type = "#v_ice_type_damage_log",
        from = data.from.id,
        --log.to是数组
        to = {data.to.id},
      }
      -- local card_id = room:askForCardChosen(data.from, data.to, "he", fk.ReasonDiscard)
      -- room:throwCard(card_id, self.name, data.to, data.from)
      local card_id = room:askForCardChosen(player, data.to, "he", self.name)
      room:throwCard(card_id, self.name, data.to, player)
      -- if data.from:isAlive() and data.to:isAlive() and not data.to:isNude() then
      if player:isAlive() and data.to:isAlive() and not data.to:isNude() then
        -- local card_id = room:askForCardChosen(data.from, data.to, "he", fk.ReasonDiscard)
        -- room:throwCard(card_id, self.name, data.to, data.from)
        local card_id = room:askForCardChosen(player, data.to, "he", self.name)
        room:throwCard(card_id, self.name, data.to, player)
      end
      --被防止的伤害仍为传导伤害。
      if data.chain and data.to.chained then
        room:sendLog{
          type = "#v_ice_type_damage_log2",
          --log.to是数组
          to = {data.to.id},
        }
        data.to:setChainState(false)
      end
      return true
    end
  end,
}

-- Fk:addSkill(v_ice_type_damage)

VslAuxSkills = {
  Swap_Invalidity,
  damage_checker_turn,
  target_specified_check,
  card_use_checker,
  mark_cleaner,
  pile_cleaner,
  v_trueround,
  v_exhaustion,
  v_ice_type_damage,
}

for _,i in ipairs(VslAuxSkills) do
  table.insert(AuxSkills, i)
end
